home *** CD-ROM | disk | FTP | other *** search
/ Sprite 1984 - 1993 / Sprite 1984 - 1993.iso / lib / tex / texindex.shar / texindex.pas next >
Pascal/Delphi Source File  |  1988-04-18  |  32KB  |  1,071 lines

  1. Program TEXIndex (Input,Output,InputFile,OutputFile);
  2.  
  3. {
  4.           XXXXX  XXXXX  X   X  XXX  X   X  XXX    XXXXX  X   X 
  5.             X    X      X   X   X   XX  X  X  X   X      X   X 
  6.             X    X       X X    X   XX  X  X   X  X       X X  
  7.             X    XXXX     X     X   X X X  X   X  XXXX     X   
  8.             X    X       X X    X   X  XX  X   X  X       X X  
  9.             X    X      X   X   X   X  XX  X  X   X      X   X 
  10.             X    XXXXX  X   X  XXX  X   X  XXX    XXXXX  X   X 
  11.  
  12. **********************************************************************
  13. Creation Date: 2/82
  14.  
  15. Author  : Skip Montanaro
  16.  
  17. Address : Lawrence Livermore National Laboratory
  18.           PO 808 / L-226
  19.           Livermore, CA 94550
  20.  
  21. Revision History:
  22.  
  23.         First Usable Version :                  2/25/82
  24.         Accepts command line :                  11/24/86
  25.  
  26. Credits:
  27.  
  28. The original version of this program was written by Terry Winograd and 
  29. Bill Paxton in INTERLISP. The TEX macro definitions necessary to generate 
  30. TEXIndex's input file and the INTERLISP program can be found in TUGBOAT, 
  31. Volume 1, Number 1, Appendix A.
  32.  
  33. Running TEXINDEX:
  34.  
  35. (TEXINDEX is RUN from INDEX.COM. That file just prompts for an input file 
  36. name and ASSIGNs the input and output logical names necessary for the
  37. program.)
  38.  
  39. Changed to accept file name on the command line.
  40.  
  41. Input Requirements:
  42.  
  43. This program expects an input file composed of references as syntactically
  44. described in CSRG:[MONTANRO.TEX]INDEX.SYN. The normal way to create that
  45. file is to let TEX generate them using the macro definitions found in
  46. Appendix A of TUGBOAT, Vol. 1, No. 1. Alternately, the file can be created by
  47. hand, although this is not feasible for long files.
  48.  
  49. Output:
  50.  
  51. The output is written to INDEXOUT.TEX and is a file of TEX macros. The
  52. output file is then run through TEX again (with suitable \input files)
  53. to create the final index.
  54.  
  55. Options:
  56.  
  57. Two options exist for the user of TEXINDEX. The first concerns the output
  58. format of the final index. The user must \let\indexEntry= one of
  59. \indexLine, \indexPar or \indexComb. This is described completely in
  60. the article in TUGBOAT. The other option is control of span elision.
  61. For instance, the reference span 947-956 is written as 947-56. Page 956
  62. has been elided. To control span elision the user can change the value of
  63. the constant, Elide, at the beginning of the program. It is not anticipated
  64. that this will change very often, so it is not asked for by the program.
  65.  
  66. **********************************************************************
  67. PROCEDURE and FUNCTION nesting
  68. Procedure GetSymbol
  69.     Function Upshift
  70.     Procedure GetCharacter
  71. Procedure SyntaxError
  72. Procedure Accept
  73. Procedure SemanticError
  74. Procedure Reference
  75.     Procedure ProcessRef
  76.         Procedure DebugPrint
  77.         Function Search
  78.             Function Enter
  79.         Function SearchPageList
  80.             Function EnterPage
  81.             Function HigherPrecedenceOf
  82. Procedure Dump
  83.     Procedure TraversePageList
  84.         Function AlteredEndPage
  85.     Procedure TraverseCrossRefs
  86. }
  87. { }
  88.  
  89.  
  90.     Label
  91.  
  92.         1,9999;
  93.  
  94.     Const
  95.  
  96.         { Settable by user to control elision of page numbers in reference
  97.           spans. }
  98.         Elide           = True;
  99.  
  100.         Space           = ' ';
  101.         Tab             = '     ';
  102.  
  103.         MaxAlfa = 80;                                   { arbitrarily long }
  104.         NullName =                                      { MaxAlfa spaces }
  105. '                                                                                ';
  106.         MaxLineLength   = 132;                          { arbitrary }
  107.  
  108.     Type
  109.  
  110.         { Symbols }
  111.         SymbolType = (Identifier, Semicolon, RightAngle, LeftAngle,
  112.                       Null);
  113.  
  114.         ErrorType = (SpanOpen,NoSpanStart,NoSpanClose,UnexpectedSymbol,
  115.                      TwoSpansOnPage);
  116.  
  117.         AlfaLength = 0..MaxAlfa;
  118.         AlfaRange = 1..MaxAlfa;
  119.         Alfa = Packed Array [AlfaRange] of Char;
  120.  
  121.         LineRange = 1..MaxLineLength;
  122.         InputLine = Packed Array [LineRange] of Char;
  123.  
  124.         { Symbol Table Stuff }
  125.  
  126.         PagePtr = ^PageRef;
  127.         TableEntryPtr = ^TableEntry;
  128.  
  129.         { Binary tree sorted by value of StartPage }
  130.         PageRef = Record
  131.             LowerPage,
  132.             HigherPage : PagePtr;
  133.             Font,               { font used to print reference }
  134.             RefType : Char;     { type of reference - normal, span, following
  135.                                   folio or note }
  136.             StartPage,
  137.             EndPage : Integer
  138.         End;
  139.  
  140.         { Binary tree sorted by value of SortedSpelling }
  141.         TableEntry = Record
  142.             Spelling,                   { entry name }
  143.             SortedSpelling : Alfa;      { upshifted - used only for sorting }
  144.             SpellLength : AlfaLength;   { length of name in character array }
  145.             PageList,                   { binary tree of page references for
  146.                                           this particular entry }
  147.             LastEndSpan,                { last span reference closed }
  148.             LastSpan : PagePtr;         { last span reference opened - Nil if
  149.                                           none are currently open }
  150.             NextLevel : TableEntryPtr;  { root of binary tree of subheadings }
  151.             CrossRefList : TableEntryPtr;
  152.                                         { root of binary tree of cross
  153.                                           references to this entry }
  154.             LeftChild,
  155.             RightChild : TableEntryPtr
  156.         End;
  157. { }
  158.  
  159.  
  160.     Var
  161.  
  162.         FormFeed : Char;                { ASCII Form Feed }
  163.  
  164.         Symbol : SymbolType;            { Last symbol parsed }
  165.         Ch : Char;                      { Last character parsed }
  166.         PageValue : Integer;            { Numeric value of last page number }
  167.         Spelling,                       { Spelling of last identifier
  168.                                           or number }
  169.         SortedSpelling : Alfa;
  170.         SymbolLength : AlfaLength;      { Length of last identifier }
  171.         Line : InputLine;               { Current input line }
  172.         CharCount,                      { Character position in Line }
  173.         LineLength                      { Length of current input line }
  174.             : 0..MaxLineLength;
  175.         LineNumber : 0..Maxint;         { Current Line Number }
  176.         SymbolTable : TableEntryPtr;
  177.  
  178.         InputFile,                      { User input file }
  179.         OutputFile : Text;              { User output file }
  180.  
  181.         LastLetter : Char;              { Current index letter being dumped }
  182.  
  183.         LastRefPrinted : Char;          { Used to see if \pageNumDot must be
  184.                                           printed after the last reference
  185.                                           that is following folio or note. }
  186.  
  187. Value
  188.  
  189.         { Compile time initialization }
  190.         LastRefPrinted := Space;
  191.         LastLetter := Space;
  192.         { Ch = Space guarantees GetSymbol calls GetCharacter when first called }
  193.         Ch := Space;
  194.         { CharCount = LineLength guarantees the first line will be read }
  195.         CharCount := 0;
  196.         LineLength := 0;
  197.         { Empty symbol table }
  198.         SymbolTable := Nil;
  199.         { identifiers full of blanks }
  200.         Spelling := NullName;
  201.         SortedSpelling := NullName;
  202. { }
  203.  
  204.  
  205. Procedure GetSymbol;
  206. { Updates: Symbol, Spelling, SortedSpelling, SymbolLength, PageValue }
  207. { Refers to: Ch, FormFeed }
  208. { Calls: GetCharacter, UpShift }
  209. { Picks off the next symbol in the input stream }
  210.  
  211. Var
  212.   i : integer ;  { locally used indexing variable }
  213.  
  214.  
  215.  
  216.     Function Upshift
  217.     ( { Using } Ch :                    Char)
  218.       { Returning } :                   Char;
  219.     { If Ch is a letter it returns the uppercase of Ch, otherwise it returns Ch }
  220.  
  221.     Begin { UpShift }
  222.  
  223.         If Ch in ['a'..'z'] then
  224.             Upshift := Chr (ord('A') + ord(Ch) - ord('a'))
  225.         Else Upshift := Ch
  226.  
  227.     End; { UpShift }
  228.  
  229.  
  230.  
  231.     Procedure GetCharacter;
  232.     { Updates: Ch, Line, CharCount, LineLength }
  233.     { Refers to: InputFile }
  234.     { Calls: Read, Eof, Eoln }
  235.     { Fetches next character from the input stream }
  236.  
  237.     Var
  238.       Clear : integer;  { locally used indexing variable
  239.                           used to blank Line }
  240.  
  241.     Begin { Get Character }
  242.  
  243.         If CharCount = LineLength then Begin
  244.  
  245.             { Quit processing input if EOF }
  246.             If Eof (InputFile) then goto 1;
  247.  
  248.             { Read next input line }
  249.             LineLength := 0;
  250.             CharCount := 0;
  251.             For Clear := 1 to MaxLineLength do
  252.                 Line[Clear] := Space;
  253.             LineNumber := LineNumber + 1;
  254.             While not Eoln (InputFile) do Begin
  255.                 LineLength := LineLength + 1;
  256.                 Read (InputFile, Ch);
  257.                 Line[LineLength] := Ch
  258.             End; { While }
  259.             LineLength := LineLength + 1;
  260.             Read (InputFile, Ch); { read past Eoln }
  261.             Line[LineLength] := Ch;
  262.  
  263.             { Pass all lines that do not begin with '<' directly to the
  264.               output file }
  265.             If Line[1] <> '<' then Begin
  266.                 Writeln ( OutputFile, Line:MaxLineLength );
  267.                 LineLength := 0;
  268.                 GetCharacter
  269.             End;
  270.  
  271.             { First character on the line }
  272.             CharCount := 1;
  273.             Ch := Line[CharCount]
  274.  
  275.         End { If CharCount = LineLength }
  276.  
  277.         Else Begin
  278.  
  279.             { Advance to next character on line }
  280.             CharCount := CharCount + 1;
  281.             Ch := Line[CharCount]
  282.  
  283.         End
  284.  
  285.     End; { Get Character }
  286. { }
  287.  
  288.  
  289. Begin { Get Symbol }
  290.  
  291.     While Ch in [Space, Tab, FormFeed] do 
  292.         GetCharacter;
  293.  
  294.     Case Ch of
  295.  
  296.     ';' : Begin
  297.         Symbol := Semicolon;
  298.         GetCharacter
  299.     End; { ';' }
  300.  
  301.     '<' : Begin
  302.         Symbol := LeftAngle;
  303.         GetCharacter
  304.     End; { '<' }
  305.  
  306.     '>' : Begin
  307.         Symbol := RightAngle;
  308.         GetCharacter
  309.     End; { '>' }
  310.  
  311.     '0','1','2','3','4','5','6','7','8','9' : Begin
  312.         Symbol := Identifier;
  313.         PageValue := ord (Ch) - ord ('0');
  314.         GetCharacter;
  315.         While Ch in ['0'..'9'] do Begin
  316.             PageValue := PageValue * 10 + ord (Ch) - ord('0');
  317.             GetCharacter
  318.         End; { While }
  319.         Spelling := NullName;
  320.         SortedSpelling := NullName
  321.     End; { Ch in ['0'..'9'] }
  322.  
  323.     Otherwise Begin 
  324.     { everything else - usually alphabetic - but anything except '<', '>'
  325.       and ';' is allowed }
  326.         Symbol := Identifier;
  327.         { blank now so we don't have to blank pad after parsing identifier }
  328.         Spelling := NullName;
  329.         SortedSpelling := NullName;
  330.  
  331.         { first character }
  332.         Spelling[1] := Ch;
  333.         SortedSpelling[1] := UpShift (Ch);
  334.         SymbolLength := 1;
  335.         GetCharacter;
  336.  
  337.         { fetch the rest }
  338.         While not (Ch in ['<','>',';']) do Begin
  339.  
  340.             { test prevents overflowing character array ==> truncate long
  341.               identifiers }
  342.             If SymbolLength <= MaxAlfa then Begin
  343.                 SymbolLength := SymbolLength + 1;
  344.                 Spelling[SymbolLength] := Ch;
  345.                 SortedSpelling[SymbolLength] := UpShift (Ch)
  346.             End;
  347.             GetCharacter
  348.         End ; { While }
  349.  
  350.         { Symbols that start with a single '\' represent special characters.
  351.           As such, they should appear together.  Symbols that start with
  352.           '\\' represent index entries that should papear as '\entry' in the
  353.           index.  In this case, the leading '\' should be ignored in the
  354.           alphabetic sort }
  355.  
  356.         { Look for \\entry }
  357.         If SymbolLength >= 2 then
  358.             If ( SortedSpelling[ 1 ] = '\' ) and
  359.                ( SortedSpelling[ 2 ] = '\' ) then
  360.                 If SymbolLength = 2 then Begin  { was exactly \\ }
  361.                     SortedSpelling[ 1 ] := Space ;
  362.                     SortedSpelling[ 2 ] := Space
  363.                 End { then }
  364.                 Else Begin  { was \\entry - make just entry }
  365.                     For i := 3 to SymbolLength Do
  366.                         SortedSpelling[ i-2 ] := SortedSpelling[ i ] ;
  367.                     SortedSpelling[ SymbolLength - 1 ] := Space ;
  368.                     SortedSpelling[ SymbolLength     ] := Space
  369.                 End { else }
  370.  
  371.     End { Otherwise }
  372.  
  373.     End { Case }
  374.  
  375. End; { Get Symbol }
  376. { }
  377.  
  378.  
  379.  
  380.  
  381. Procedure SyntaxError
  382. ( { Using }  ErrorSymbol :                      ErrorType;
  383.              ExpectedSymbol :                   SymbolType);
  384. { Displays appropriate error message on terminal }
  385.  
  386. Begin { Syntax Error }
  387.  
  388.     Write ('Syntax Error --> ');
  389.     Case ErrorSymbol of
  390.         UnexpectedSymbol : Writeln ('Unexpected ',Symbol:10,
  391.                          ' found in input stream. ',ExpectedSymbol:10,
  392.                          ' was expected.')
  393.     End { Case ErrorSymbol }
  394.  
  395. End; { Syntax Error }
  396.  
  397.  
  398. Procedure Accept
  399. ( { Using } ExpectedSymbol :                Symboltype);
  400. { Refers to: Symbol }
  401. { Calls: GetSymbol }
  402. { Checks to make sure the proper symbol is present in the input text and 
  403.   advances the parser to the next symbol. If an unexpected symbol is found, 
  404.   an error message is generated and the old symbol is retained }
  405.  
  406. Begin { Accept }
  407.  
  408.     if Symbol = ExpectedSymbol then
  409.         GetSymbol
  410.     Else
  411.         SyntaxError (UnexpectedSymbol,ExpectedSymbol)
  412.  
  413. End; { Accept }
  414.  
  415.  
  416.  
  417. Procedure SemanticError
  418. ( { Using }  ErrorSymbol :                      ErrorType;
  419.              PageValue :                        Integer);
  420. { Displays appropriate error message on terminal }
  421.  
  422. Begin { Semantic Error }
  423.  
  424.     Write ('Semantic Error --> ');
  425.     Case ErrorSymbol of
  426.  
  427.         NoSpanStart : Writeln ('No reference span open on page ',
  428.                          PageValue:1,' during attempt to close span.');
  429.  
  430.         SpanOpen : Writeln ('Reference span already open during attempt ',
  431.                          'to open span on page ',PageValue:1,'.');
  432.  
  433.         NoSpanClose : Writeln ('Reference span that started on page ',
  434.                          PageValue:1,' was never closed.');
  435.  
  436.         TwoSpansOnPage : Writeln ('Two span references present on ',
  437.                          PageValue:1,'.')
  438.  
  439.     End { Case ErrorSymbol }
  440.  
  441. End; { Semantic Error }
  442.  
  443.  
  444.  
  445. { }
  446.  
  447.  
  448.  
  449. Procedure Reference;
  450. { Refers to: Symbol, Spelling, SortedSpelling, SymbolLength }
  451. { Calls: Accept, ProcessRef }
  452. { Parses a single reference }
  453.  
  454. Var
  455.  
  456.     Field1,
  457.     SortedField1 : Alfa;
  458.     Field1Length : AlfaLength;
  459.     FontType,
  460.     RefType : Char;
  461.  
  462.  
  463.  
  464.     Procedure ProcessRef
  465.     ( { Using }  Target,
  466.                  SortedTarget :                 Alfa;
  467.                  TargetLength :                 AlfaLength;
  468.                  FontType,
  469.                  RefType :                      Char);
  470.     { Refers to : PageValue }
  471.     { Calls: DebugPrint (diagnostic only), Search, Accept, SearchPageList,
  472.       SemanticError
  473.     { Enters References in symbol table }
  474.  
  475.     Var
  476.  
  477.         Entry : TableEntryPtr ;
  478.         PageEntry : PagePtr;
  479.  
  480.         Procedure DebugPrint
  481.         ( { Using } Root :                              TableEntryPtr;
  482.                     Indent :                            Integer);
  483.         { Dumps Symbol Table }
  484.  
  485.         Begin { Debug Print }
  486.  
  487.             With Root^ do
  488.  
  489.                 If Root <> Nil then Begin
  490.                     Writeln (' ':Indent,Spelling:SpellLength);
  491.                     DebugPrint (LeftChild,Indent+2);
  492.                     DebugPrint (RightChild,Indent+2)
  493.                 End { If }
  494.  
  495.         End; { Debug Print }
  496. { }
  497.  
  498.  
  499.  
  500.         Function Search
  501.         ( { Using }  Name,
  502.                      SortedName :                       Alfa;
  503.                      NameLength :                       AlfaLength;
  504.                      FontType,
  505.                      RefType :                          Char;
  506.           { Alters } Var Root :                         TableEntryPtr)
  507.           { Returns } :                                 TableEntryPtr;
  508.         { Searches tree headed by Root for Name, creating entry if not found.
  509.           returns a pointer to the found/created entry. }
  510.  
  511.         Var
  512.  
  513.             Last,
  514.             Temp : TableEntryPtr;
  515.             Finished,
  516.             LeftTaken : Boolean;
  517.  
  518.             Function Enter
  519.             { Returns } :                               TableEntryPtr;
  520.             { Refers to: Name, SortedName, NameLength }
  521.             { Creates an entry in the symbol table }
  522.  
  523.             Var
  524.  
  525.                 Entry : TableEntryPtr;
  526.  
  527.             Begin { Enter }
  528.  
  529.                 New (Entry);
  530.                 With Entry^ do Begin
  531.                     Spelling := Name;
  532.                     SortedSpelling := SortedName;
  533.                     SpellLength := NameLength;
  534.                     PageList := Nil;
  535.                     LastSpan := Nil;
  536.                     NextLevel := Nil;
  537.                     CrossRefList := Nil;
  538.                     LeftChild := Nil;
  539.                     RightChild := Nil
  540.                 End; { With Entry^ }
  541.                 Enter := Entry
  542.  
  543.             End; { Enter }
  544. { }
  545.  
  546.  
  547.  
  548.         Begin { Search }
  549.             If Root = Nil then Begin { Empty Tree - create new entry }
  550.                 Root := Enter;
  551.                 Search := Root
  552.  
  553.             End
  554.             Else Begin
  555.                 Temp := Root;
  556.  
  557.                 { Binary Search of Tree headed by Temp }
  558.                 Finished := Temp^.SortedSpelling = SortedName;
  559.  
  560.                 While Not Finished do Begin
  561.  
  562.                     { If another loop is necessary, which branch will we take? }
  563.                     LeftTaken := Temp^.SortedSpelling > SortedName;
  564.  
  565.                     { Save where we came from }
  566.                     Last := Temp;
  567.  
  568.                     { Take appropriate branch }
  569.                     If LeftTaken then
  570.                         Temp := Last^.LeftChild
  571.                     Else
  572.                         Temp := Last^.RightChild;
  573.  
  574.                     { If we run out of entries then back up one and create an entry }
  575.                     If Temp = Nil then Begin
  576.  
  577.                         Temp := Enter;
  578.                         If LeftTaken then
  579.                             Last^.LeftChild := Temp
  580.                         Else
  581.                             Last^.RightChild := Temp
  582.  
  583.                     End; { Else }
  584.  
  585.                     Finished := Temp^.{Sorted}Spelling = {Sorted}Name
  586.  
  587.                 End; { While Not Finished }
  588.                 Search := Temp
  589.  
  590.             End { Else Begin }
  591.  
  592.         End; { Search }
  593. { }
  594.  
  595.         Function SearchPageList
  596.         ( { Using } PageValue :                         Integer;
  597.                     FType, { Font Type }
  598.                     RType : { Ref Type }                Char;
  599.           { Alters }Var Root :                          PagePtr)
  600.           { Returns } :                                 PagePtr;
  601.         { Similar to Search, but looks through page lists. }
  602.  
  603.         Var
  604.  
  605.             Temp,
  606.             Last : PagePtr;
  607.             Finished,
  608.             LeftTaken : Boolean;
  609.  
  610.  
  611.             Function EnterPage
  612.             { Returns } :                               PagePtr;
  613.             { Creates an entry in the page list symbol table }
  614.  
  615.             Var
  616.  
  617.                 Entry : PagePtr;
  618.  
  619.             Begin { Enter Page }
  620.  
  621.                 New (Entry);
  622.                 With Entry^ do Begin
  623.                     StartPage := PageValue;
  624.                     EndPage := -1;
  625.                     RefType := RType;
  626.                     Font := FType;
  627.                     LowerPage := Nil;
  628.                     HigherPage := Nil
  629.                 End; { With Entry^ }
  630.                 EnterPage := Entry
  631.  
  632.             End; { Enter Page }
  633. { }
  634.  
  635.  
  636.             Function HigherPrecedenceOf
  637.             ( { Using } RType1,
  638.                         RType2 :                        Char)
  639.               { Returns } :                             Char;
  640.             { Picks higher precedence reference type }
  641.  
  642.             Var
  643.  
  644.                 RefSet : Set of Char;
  645.  
  646.             Begin { Higher Precedence Of }
  647.  
  648.                 RefSet := [RType1,RType2];
  649.  
  650.                 If 'S' in RefSet then
  651.                     HigherPrecedenceOf := 'S'
  652.                 Else If 'F' in RefSet then
  653.                     HigherPrecedenceOf := 'F'
  654.                 Else if 'N' in RefSet then
  655.                     HigherPrecedenceOf := 'N'
  656.                 Else
  657.                     HigherPrecedenceOf := 'P'
  658.  
  659.             End; { Higher Precedence Of }
  660. { }
  661.  
  662.  
  663.         Begin { Search Page List }
  664.  
  665.             If Root = Nil then Begin { Empty Tree - create new entry }
  666.                 Root := EnterPage;
  667.                 SearchPageList := Root
  668.  
  669.             End
  670.             Else Begin
  671.                 Temp := Root;
  672.  
  673.                 { Binary Search of Tree headed by Temp }
  674.                 Finished := Temp^.StartPage = PageValue;
  675.  
  676.                 While Not Finished do Begin
  677.  
  678.                     { If another loop is necessary, which branch will we take? }
  679.                     LeftTaken := Temp^.StartPage > PageValue;
  680.  
  681.                     { Save where we came from }
  682.                     Last := Temp;
  683.  
  684.                     { Take appropriate branch }
  685.                     If LeftTaken then
  686.                         Temp := Last^.LowerPage
  687.                     Else
  688.                         Temp := Last^.HigherPage;
  689.  
  690.                     { If we run out of entries then back up one and create an entry }
  691.                     If Temp = Nil then Begin
  692.  
  693.                         Temp := EnterPage;
  694.                         If LeftTaken then
  695.                             Last^.LowerPage := Temp
  696.                         Else
  697.                             Last^.HigherPage := Temp
  698.  
  699.                     End; { Else }
  700.  
  701.                     Finished := Temp^.StartPage = PageValue
  702.  
  703.                 End; { While Not Finished }
  704.  
  705.                 { Error if last span ends on same page the current one
  706.                   begins on, if a span is even active }
  707.                 With Entry^ do
  708.                     If LastSpan <> Nil then
  709.                         If LastEndSpan^.EndPage = Temp^.StartPage then
  710.                             SemanticError (TwoSpansOnPage,Temp^.StartPage);
  711.  
  712.                 Temp^.RefType := HigherPrecedenceOf (Temp^.RefType,RType);
  713.  
  714.                 SearchPageList := Temp
  715.  
  716.             End { Else Begin }
  717.  
  718.         End; { Search Page List }
  719. { }
  720.  
  721.  
  722.  
  723.     Begin { Process Ref }
  724.  
  725.         Entry := 
  726.             Search (Spelling,SortedSpelling,SymbolLength,FontType,
  727.                 RefType,SymbolTable);
  728.         Accept (Identifier);
  729.         While Symbol = Semicolon do Begin
  730.            Accept (Semicolon);
  731.            Entry :=
  732.                Search (Spelling,SortedSpelling,SymbolLength,FontType,
  733.                    RefType,Entry^.NextLevel);
  734.            Accept (Identifier)
  735.         End; { While }
  736.  
  737.         Case RefType of 
  738.  
  739.             'C' : Entry :=
  740.                 Search (Target,SortedTarget,TargetLength,
  741.                     FontType,RefType,Entry^.CrossRefList);
  742.  
  743.             'P' : PageEntry := 
  744.                 SearchPageList (PageValue,FontType,RefType,Entry^.PageList);
  745.  
  746.             'F' : PageEntry := 
  747.                 SearchPageList (PageValue,FontType,RefType,Entry^.PageList);
  748.  
  749.             'S' : With Entry^ do 
  750.                 If LastSpan <> Nil then
  751.                     SemanticError (SpanOpen,PageValue)
  752.                 Else
  753.                     LastSpan := SearchPageList (PageValue,FontType,RefType,
  754.                         Entry^.PageList);
  755.  
  756.             'E' : With Entry^ do Begin
  757.                 If LastSpan = Nil then
  758.                     SemanticError (NoSpanStart,PageValue)
  759.                 Else if LastSpan^.StartPage = PageValue then
  760.                     LastSpan^.RefType := 'P'
  761.                 Else Begin
  762.                     LastSpan^.EndPage := PageValue;
  763.                     LastEndSpan := LastSpan
  764.                 End;
  765.                 LastSpan := Nil
  766.             End; { Case 'E' }
  767.  
  768.             'N' : PageEntry := 
  769.                 SearchPageList (PageValue,FontType,RefType,Entry^.PageList)
  770.  
  771.         End { Case RefType }
  772.  
  773.     End; { Process Ref }
  774. { }
  775.  
  776.  
  777.  
  778.  
  779. Begin { Reference }
  780.  
  781.     Accept (LeftAngle);
  782.  
  783.     { If the identifier present is a page number its value is stored in the
  784.       global variable, PageValue; Spelling and SortedSpelling are both blank. }
  785.     Field1 := Spelling;
  786.     SortedField1 := SortedSpelling;
  787.     Field1Length := SymbolLength;
  788.     Accept (Identifier);
  789.     Accept (Semicolon);
  790.  
  791.     FontType := SortedSpelling[1];
  792.     Accept (Identifier);
  793.     Accept (Semicolon);
  794.  
  795.     RefType := SortedSpelling[1];
  796.     Accept (Identifier);
  797.     Accept (Semicolon);
  798.  
  799.     ProcessRef (Field1,SortedField1,Field1Length,FontType,RefType);
  800.  
  801.     Accept (RightAngle)
  802.  
  803. End; { Reference }
  804. { }
  805.  
  806.  
  807. Procedure Dump
  808. ( { Using } Root :                      TableEntryPtr;
  809.             Level :                     Integer);
  810. { Traverses and prints the symbol table in order }
  811.  
  812.  
  813.  
  814.     Procedure TraversePageList
  815.     ( { Using } PageRoot :                      PagePtr;
  816.                 ElideRefs :                     Boolean);
  817.     { Traverses and prints the Page List Tree, with optional Eliding }
  818.  
  819.     Const
  820.  
  821.         Comma = ', ';
  822.  
  823.     Var
  824.  
  825.         I : Integer;
  826.  
  827.         Function AlteredEndPage
  828.         ( { Using } StartP,
  829.                     EndP :                      Integer)
  830.           { Returns } : Integer;
  831.         { Returns that part of EndP to be printed, taking elision into account. }
  832.  
  833.         Begin { Altered End Page }
  834.  
  835.             If (StartP mod 100 = 0) or not ElideRefs then
  836.                 AlteredEndPage := EndP
  837.             Else
  838.                 AlteredEndPage := EndP mod 100
  839.  
  840.         End; { Altered End Page }
  841. { }
  842.  
  843.  
  844.     Begin { Traverse Page List }
  845.  
  846.         With PageRoot^ do Begin
  847.  
  848.             If LowerPage <> Nil then
  849.                 TraversePageList (LowerPage,ElideRefs);
  850.  
  851.             Write (OutputFile,Comma);
  852.  
  853.             If Font = 'B' then
  854.                 Write (OutputFile,'\mainEntry{');
  855.  
  856.             Case RefType of
  857.  
  858.                 'S' : Begin
  859.  
  860.                     If EndPage = -1 then
  861.                         SemanticError (NoSpanClose,StartPage);
  862.                     Write (OutputFile,'\indexSpan ',StartPage:1,'-');
  863.                     EndPage := AlteredEndPage (StartPage,EndPage);
  864.                     Write (OutputFile,EndPage:1,'.')
  865.  
  866.                 End; { RefType = 'S' }
  867.  
  868.                 'F' : Write (OutputFile,'\indexFF ',StartPage:1,'.');
  869.  
  870.                 'N' : Write (OutputFile,'\indexN ',StartPage:1,'.');
  871.  
  872.                 'P' : Write (OutputFile,StartPage:1)
  873.  
  874.             End; { Case RefType of }
  875.  
  876.             LastRefPrinted := RefType;
  877.  
  878.             If Font = 'B' then
  879.                 Write (OutputFile,'}');
  880.  
  881.             If HigherPage <> Nil then
  882.                 TraversePageList (HigherPage,ElideRefs)
  883.  
  884.         End { With }
  885.  
  886.     End; { Traverse Page List }
  887. { }
  888.  
  889.  
  890.     Procedure TraverseCrossRefs
  891.     ( { Using } CrossRoot :                     TableEntryPtr);
  892.     { Traverses and prints the Cross Reference list }
  893.  
  894.     Const
  895.  
  896.         Comma = ', ';
  897.  
  898.     Begin { Traverse Cross Refs }
  899.  
  900.         With CrossRoot^ do Begin
  901.             { Traverse left subtree }
  902.             If LeftChild <> Nil then Begin
  903.                 TraverseCrossRefs (LeftChild);
  904.                 Write (OutputFile,Comma)
  905.             End;
  906.  
  907.             { Print this node }
  908.             Write (OutputFile,Spelling:SpellLength);
  909.  
  910.             { Traverse Right subtree }
  911.             If RightChild <> Nil then Begin
  912.                 Write (OutputFile,Comma);
  913.                 TraverseCrossRefs (RightChild)
  914.             End
  915.         End { With CrossRoot^ }
  916.  
  917.     End; { Traverse Cross Refs }
  918. { }
  919.  
  920.  
  921.  
  922. Begin { Dump }
  923.  
  924.     With Root^ do Begin
  925.  
  926.         { Traverse Left Sub-tree }
  927.         If LeftChild <> Nil then
  928.             Dump (LeftChild,Level);
  929.  
  930.         { Dump this node }
  931.  
  932.         If (LastLetter <> SortedSpelling[1]) and (Level = 0) then Begin
  933.             Writeln (OutputFile,'\indexChar{',SortedSpelling[1],'}');
  934.             LastLetter := SortedSpelling[1]
  935.         End;
  936.  
  937.         Write (OutputFile,'\indexEntry',Level:1,'{',Spelling:SpellLength);
  938.         If PageList <> Nil then Begin
  939.             Write (OutputFile, '\') ;
  940.             TraversePageList (PageList,Elide);
  941.             If LastRefPrinted in ['F','N'] then
  942.                 Write (OutputFile,'\pageNumDot')
  943.         End;
  944.         Write (OutputFile,'}{{');
  945.  
  946.         If CrossRefList <> Nil then Begin
  947.             If PageList <> Nil then
  948.                 Write (OutputFile,'\indexAlso{')
  949.             Else Write (OutputFile,'\indexSee{');
  950.             TraverseCrossRefs (CrossRefList);
  951.             Write (OutputFile,'}')
  952.         End;
  953.  
  954.         Write (OutputFile,'}');
  955.  
  956.         If NextLevel <> Nil then Begin
  957.             Writeln (OutputFile,'+{');
  958.             Dump (NextLevel,Level+1);
  959.             Writeln (OutputFile,'}}')
  960.         End
  961.         Else Writeln (OutputFile,'-{}}');
  962.  
  963.         { Traverse Right Sub-tree }
  964.         If RightChild <> Nil then
  965.             Dump (RightChild,Level)
  966.  
  967.     End { With Root^ }
  968.  
  969. End; { Dump }
  970. { }
  971.  
  972. procedure OpenFiles;
  973.  
  974. type
  975.    word= 0..65535;
  976. var
  977.   command_line:packed array[1..300] of char;
  978.   cmd_len:word;
  979.   cmd_i:integer;
  980.   file_name,def_file_name:varying [300] of char;
  981.   ask,got_file_name: boolean;
  982.  
  983. [external] function lib$get_foreign(
  984.   %stdescr cmdlin:[volatile] packed array [$l1..$u1:integer] of char
  985.         := %immed 0;
  986.   %stdescr prompt:[volatile] packed array [$l2..$u2:integer] of char
  987.         := %immed 0;
  988.   var len : [volatile] word := %immed 0;
  989.   var flag : [volatile] integer := %immed 0)
  990.     :integer; extern;
  991.  
  992. begin { OpenFiles }
  993.   cmd_i:=0;
  994.   lib$get_foreign(command_line,,cmd_len,cmd_i);
  995.   cmd_i:=1;
  996.   while (cmd_i<=cmd_len) and (command_line[cmd_i]=' ') do cmd_i:=cmd_i+1;
  997.   got_file_name:=cmd_i<=cmd_len;
  998.   if got_file_name then
  999.         def_file_name:=substr(command_line,cmd_i,cmd_len-cmd_i+1);
  1000.  
  1001.   if got_file_name then begin
  1002.         file_name:=def_file_name+'.IDX';
  1003.         open(InputFile,file_name,readonly, error:=continue);
  1004.         ask:=status(InputFile)<>0;
  1005.         if ask then writeln('Couldn''t open ',file_name);
  1006.         end
  1007. else ask:=true;
  1008. while ask do begin
  1009.         got_file_name:=false;
  1010.         write('Index input file: ');
  1011.         if eof then goto 9999;
  1012.         readln(file_name);
  1013.         open(InputFile,file_name,readonly, error:=continue);
  1014.         ask:=status(InputFile)<>0;
  1015.         if ask then writeln('Couldn''t open ',file_name);
  1016.         end;
  1017. reset(InputFile);
  1018.  
  1019. if got_file_name then begin
  1020.         cmd_i:=1;
  1021.         for cmd_len:=1 to def_file_name.length do
  1022.                 if (def_file_name[cmd_len]=']')
  1023.                 or (def_file_name[cmd_len]=':')
  1024.                 then cmd_i:=cmd_len+1;
  1025.         if cmd_i<=def_file_name.length then
  1026.                 def_file_name:=substr(def_file_name,cmd_i,
  1027.                         def_file_name.length-cmd_i+1);
  1028.         file_name:=def_file_name+'.IND';
  1029.         open(OutputFile,file_name,new,32767,disposition:=delete,
  1030.                 error:=continue);
  1031.         ask:=status(OutputFile)>0;
  1032.         if ask then writeln('Couldn''t open ',file_name);
  1033.         end
  1034. else ask:=true;
  1035. while ask do begin
  1036.         write('Index output file: ');
  1037.         if eof then goto 9999;
  1038.         readln(file_name);
  1039.         open(OutputFile,file_name,new,32767,disposition:=delete,
  1040.                 error:=continue);
  1041.         ask:=status(OutputFile)>0;
  1042.         if ask then writeln('Couldn''t open ',file_name);
  1043.         end;
  1044. rewrite(OutputFile);
  1045. end;  { OpenFiles }
  1046.  
  1047. { }
  1048.  
  1049. Begin { Main Program }
  1050.  
  1051.     OpenFiles;
  1052.  
  1053.     GetSymbol;
  1054.  
  1055.     While Symbol = LeftAngle do 
  1056.         Reference;
  1057.  
  1058. 1:  Close (InputFile);
  1059.  
  1060.     if SymbolTable<>Nil then
  1061.       begin
  1062.         Writeln (OutputFile,'\indexStart');
  1063.         Dump (SymbolTable,0);
  1064.         Writeln (OutputFile,'\indexEnd');
  1065.       end
  1066.     else
  1067.         Writeln (OutputFile,'\relax');
  1068.     Close( OutputFile, disposition:=save );
  1069. 9999:
  1070. End. { Main Program }
  1071.